package com.xingkeduo.business.user.activity;

import com.alibaba.fastjson.JSON;
import com.xingkeduo.business.user.domain.FeignDomain;
import com.xingkeduo.business.user.event.EventHandleService;
import com.xingkeduo.business.user.event.MsgTempDTO;
import com.xingkeduo.business.user.event.MsgTempDTO.PushTypeEnums;
import com.xingkeduo.business.user.service.*;
import com.xingkeduo.pojo.dto.ScanDTO;
import com.xingkeduo.pojo.enums.ReceiveTypeEnums;
import com.xingkeduo.pojo.enums.SendingTypeEnum;
import com.xingkeduo.pojo.enums.ShareFromEnums;
import com.xingkeduo.pojo.enums.UserTypeEnums;
import com.xingkeduo.pojo.query.*;
import com.xingkeduo.pojo.table.*;
import com.xingkeduo.util.pojo.base.BaseTable;
import com.xingkeduo.util.pojo.enums.YesNoEnum;
import com.xingkeduo.util.pojo.exception.DataException;
import com.xingkeduo.util.pojo.exception.InputParamException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 邀请新用户领取5折券
 *
 * @Description:
 * @Author:gaozifeng
 * @Date 2019/7/12 11:32
 **/
@Slf4j
@Component("userInviteReceiveCouponService")
public class UserInviteReceiveCouponService implements UserInviteReceiveCouponStrategy {

    @Resource
    private WechatQrcodeService wechatQrcodeService;
    @Resource
    private ShareService shareService;
    @Resource
    private ShareReceiveService shareReceiveService;
    @Resource
    private ConsumerStatisticsService consumerStatisticsService;
    @Resource
    private ConsumerService consumerService;
    @Resource
    private ConsumerPrivateService consumerPrivateService;
    @Resource
    private EventHandleService eventHandleService;
    @Resource
    private FeignDomain feignDomain;
    @Resource
    private ConsumerRelateService consumerRelateService;

    /**
     * 领取   公众号(mpId,openId,sceneId) 小程序(receiveId和sceneId)
     *
     * @param scanDTO:
     * @return : void
     * @author : gaozifeng
     * @date : 2019/7/12 13:54
     */
    @Override
    public void receiveCoupon(ScanDTO scanDTO) throws Throwable {
        log.info("C拉C领取人信息[{}]", JSON.toJSONString(scanDTO));
        ShareTO shareTO;
        WechatQrcodeTO wechatQrcodeTO;
        ShareReceiveTO shareReceiveTO = new ShareReceiveTO();
        if (StringUtils.isNotBlank(scanDTO.getOpenId())) {
            //公众号是二维码表id
            wechatQrcodeTO = getWechatQrCodeById(scanDTO.getSceneId().longValue());
            //TODO 多公众号的情况下 怎么处理 openid一样的扫码事件？
            Boolean isReturn = checkSamePerson(wechatQrcodeTO.getReceiveId(), scanDTO.getOpenId());
            if (isReturn) {
                return;
            }
            shareTO = shareService.selectByPrimary(wechatQrcodeTO.getSceneId());
            shareReceiveTO.setShareId(wechatQrcodeTO.getSceneId());
        } else {
            if (null == scanDTO.getUserId()) {
                throw new InputParamException(InputParamException.Type.NULL, "领取人不能为");
            }
            if (null == scanDTO.getShareId()) {
                throw new InputParamException(InputParamException.Type.NULL, "分享信息不能为");
            }
            //小程序进来是分享id
            shareTO = shareService.selectByPrimary(scanDTO.getShareId());
            shareReceiveTO.setShareId(shareTO.getId());
        }
        ConsumerTO consumerInfo = consumerService.selectByPrimary(shareTO.getConsumerId());
        if (null == consumerInfo) {
            throw new DataException(DataException.Type.NULL, "邀请人");
        }
        Long receiveId;
        if (shareTO.getShareFrom() == ShareFromEnums.WX_GZH) {
            receiveId = getReceiveId(scanDTO.getOpenId());
        } else {
            ConsumerTO receiveInfo = getReceiveInfoById(scanDTO.getUserId());
            receiveId = receiveInfo.getId();
        }
        //查询是否可以领券
        checkUserReceivePermission(receiveId, shareTO.getShareFrom());

        Map map = feignDomain.bindReceiveAccountOfShareNewUser(receiveId);
        log.info("新用户发券Map[{}]",JSON.toJSONString(map));
        Integer mapId = (Integer) map.get("id");
        long couponId = mapId.longValue();
        Integer couponType = (Integer) map.get("marketingType");
        if (couponId > 0L) {
            shareReceiveTO.setConsumerId(consumerInfo.getId()).setReceiveId(receiveId)
                    .setReceiveType(ReceiveTypeEnums.INVITE_USER).setReceiveCouponId(couponId)
                    .setReceiveCouponType(couponType).setIsDelete(YesNoEnum.NO);
            shareReceiveService.insert(shareReceiveTO);
            if (shareTO.getShareFrom() == ShareFromEnums.WX_GZH) {
                pushCustomerNew(scanDTO.getOpenId(), PushTypeEnums.NEW_CONSUMER);
            }
        } else {
            //领取失败  推送消息   抢完提醒
            if (shareTO.getShareFrom() == ShareFromEnums.WX_GZH) {
                pushCustomerNew(scanDTO.getOpenId(), PushTypeEnums.COUPON_END);
            }
            log.info("券已发完");
            throw new DataException(DataException.Type.NULL, PushTypeEnums.COUPON_END.getDesc());
        }
    }

    /**
     * 根据二维码记录id 查询
     *
     * @param id:
     * @return : com.xingkeduo.pojo.table.WechatQrcodeTO
     * @author : gaozifeng
     * @date : 2019/7/12 10:11
     */
    private WechatQrcodeTO getWechatQrCodeById(Long id) throws Throwable {
        WechatQrcodeTO wechatQrcodeTO = wechatQrcodeService.selectByPrimary(id);
        if (null == wechatQrcodeTO) {
            throw new DataException(DataException.Type.NULL, "二维码记录");
        }
        return wechatQrcodeTO;
    }

    /**
     * 获取领取人id
     * m页 应该只有公众号 没有支付宝
     *
     * @param openId:
     * @return : java.lang.Long
     * @author : gaozifeng
     * @date : 2019/7/12 11:38
     */
    private Long getReceiveId(String openId) throws Throwable {
        List<ConsumerPrivateTO> consumerPrivateList = getConsumerPrivateByGzhOpenId(openId);
        List<Long> ids = consumerPrivateList.stream().map(a -> a.getId()).collect(Collectors.toList());
        List<ConsumerTO> consumerList = consumerService.selectConsumerList(new ConsumerQO().setIds(ids).setIsDelete(YesNoEnum.NO));
        if (null == consumerList || consumerList.size() == 0) {
            throw new DataException(DataException.Type.NULL, "用户");
        }
        List<Long> receiveId = consumerList.stream()
                .filter(a -> a.getType() == UserTypeEnums.WX.getType()).map(a -> a.getId()).collect(Collectors.toList());
        return receiveId.get(0);
    }


    /**
     * 判断用户是否可以领取券权限
     *
     * @param consumerId:
     * @return : java.lang.Boolean
     * @author : gaozifeng
     * @date : 2019/7/12 12:53
     */
    private void checkUserReceivePermission(Long consumerId, ShareFromEnums shareFromEnums) throws Throwable {

        List<Long> consumerIds = getManyConsumerIds(consumerId);

        Boolean flag = checkNewConsumers(consumerIds);
        String openId = getConsumerPrivateGzhOpenId(consumerId);
        if (flag) {
            List<ShareReceiveTO> shareReceiveList = shareReceiveService.selectByQuery(new ShareReceiveQO()
                    .setReceiveId(consumerId).setReceiveType(ReceiveTypeEnums.INVITE_USER).setIsDelete(YesNoEnum.NO));
            if (null != shareReceiveList && shareReceiveList.size() > 0) {
                if (ShareFromEnums.WX_GZH == shareFromEnums && null != openId) {
                    //推送
                    pushCustomerNew(openId, PushTypeEnums.ONLY_ONE);
                }
                throw new InputParamException(InputParamException.Type.DEFAULT, PushTypeEnums.ONLY_ONE.getDesc());
            }
        } else {
            if (ShareFromEnums.WX_GZH == shareFromEnums && null != openId) {
                //推送
                pushCustomerNew(openId, PushTypeEnums.ONLY_NEW_CONSUMER);
            }
            throw new InputParamException(InputParamException.Type.DEFAULT, PushTypeEnums.ONLY_NEW_CONSUMER.getDesc());
        }
    }

    /**
     * 校验扫码和领券是否同一个人
     *
     * @param receiveId: 生成二维码的领取人用户id
     * @param openId:    扫码事件的真实领取人用户id
     * @return : void
     * @author : gaozifeng
     * @date : 2019/7/23 20:53
     */
    private Boolean checkSamePerson(Long receiveId, String openId) throws Throwable {
        List<Long> privateList = getConsumerPrivateByGzhOpenIdForIds(openId);
        if (null != privateList && privateList.size() > 0) {
            boolean contains = privateList.contains(receiveId);
            if (!contains) {
                log.info("不是相同的账号领取人[{}],openId[{}]", receiveId, openId);
                pushCustomerNew(openId, PushTypeEnums.NOT_SAME_PERSON);
                return true;
            }
        }
        return false;
    }

    private ConsumerTO getReceiveInfoById(Long id) throws Throwable {
        ConsumerTO consumerTO = consumerService.selectByPrimary(id);
        if (null == consumerTO) {
            throw new DataException(DataException.Type.NULL, "用户");
        }
        return consumerTO;
    }

    private ConsumerPrivateTO getConsumerPrivate(Long consumerId) throws Throwable {
        ConsumerPrivateTO privateTO = consumerPrivateService.selectByPrimary(consumerId);
        if (null == privateTO) {
            return null;
        }
        return privateTO;
    }

    private List<ConsumerPrivateTO> getConsumerPrivateByGzhOpenId(String openId) throws Throwable {
        List<ConsumerPrivateTO> consumerPrivateList = consumerPrivateService.selectUserPrivateList(new ConsumerPrivateQO().setGzhOpenId(openId));
        if (null == consumerPrivateList || consumerPrivateList.size() == 0) {
            throw new DataException(DataException.Type.NULL, "领取人信息");
        }
        return consumerPrivateList;
    }

    private List<Long> getConsumerPrivateByGzhOpenIdForIds(String openId) throws Throwable {
        List<Long> consumerPrivateList = consumerPrivateService.selectUserPrivateForId(new ConsumerPrivateQO().setGzhOpenId(openId));
        if (null == consumerPrivateList || consumerPrivateList.size() == 0) {
            throw new DataException(DataException.Type.NULL, "领取人信息");
        }
        return consumerPrivateList;
    }

    private String getConsumerPrivateGzhOpenId(Long consumerId) throws Throwable {
        ConsumerPrivateTO privateTO = consumerPrivateService.selectByPrimary(consumerId);
        if (null == privateTO) {
            return null;
        }
        return privateTO.getGzhOpenId();
    }

    /**
     * 获取账户合并
     *
     * @param consumerId:
     * @return : java.util.List<java.lang.Long>
     * @author : gaozifeng
     * @date : 2019/7/22 10:45
     */
    private List<Long> getManyConsumerIds(Long consumerId) throws Throwable {
        ConsumerPrivateTO consumerPrivate = getConsumerPrivate(consumerId);
        if (null != consumerPrivate) {
            if (null != consumerPrivate.getPhone()) {
                List<ConsumerRelateTO> relateList = consumerRelateService
                        .selectConsumerRelateList(new ConsumerRelateQO().setPhone(consumerPrivate.getPhone()).setIsDelete(YesNoEnum.NO));
                return relateList.stream().map(BaseTable::getId).collect(Collectors.toList());
            }
        }
        return Arrays.asList(consumerId);
    }

    /**
     * 检查多账号 是否新用户 当某一端领取之后 另一端 也不让领
     *
     * @param consumerIds:
     * @return : java.lang.Boolean
     * @author : gaozifeng
     * @date : 2019/7/22 10:56
     */
    private Boolean checkNewConsumers(List<Long> consumerIds) throws Throwable {
        List<ConsumerStatisticsTO> statistics = consumerStatisticsService
                .selectConsumerForList(new ConsumerStatisticsQO().setIds(consumerIds).setIsDelete(YesNoEnum.NO));

        Boolean flag = true;
        if (null != statistics && statistics.size() > 0) {
            long count = statistics.stream().filter(a -> null != a.getFirstPayTime()).count();
//            long count = statistics.stream().filter(a -> a.getPayCount() > 0).count();
            if (count > 0) {
                flag = false;
            }
        }

        return flag;
    }

    /**
     * 推送客服消息
     *
     * @param :
     * @return : void
     * @author : gaozifeng
     * @date : 2019/7/19 11:50
     */
    private void pushCustomerNew(String openId, PushTypeEnums pushType) {
        MsgTempDTO msgTempDTO = new MsgTempDTO();
        msgTempDTO.setOpenId(openId);
        msgTempDTO.setContent(pushType);
        eventHandleService.eventHandle(SendingTypeEnum.MSG_TEMP, msgTempDTO);
    }
}
